<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Linux命令应用">
<meta name="twitter:description" content="<p>命令：tr,sort,uniq,trap,screen,nohup,find,xargs,seq,script,pass；词频统计，执行任务防止意外中断，查找文件并删除，统计代码行数，打印九九乘法表，保留颜色格式到文件，命令行隐藏敏感信息</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/linux-command-tips.html"/>
<meta property="og:title" content="来玩魔王的咚 | Linux命令应用" />
<meta property="og:description" content="<p>命令：tr,sort,uniq,trap,screen,nohup,find,xargs,seq,script,pass；词频统计，执行任务防止意外中断，查找文件并删除，统计代码行数，打印九九乘法表，保留颜色格式到文件，命令行隐藏敏感信息</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>命令：tr,sort,uniq,trap,screen,nohup,find,xargs,seq,script,pass；词频统计，执行任务防止意外中断，查找文件并删除，统计代码行数，打印九九乘法表，保留颜色格式到文件，命令行隐藏敏感信息</p>" />

    <meta name="tags" content="shell" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li class="active"><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-08-27 15:40:00+08:00">
                <script>document.write(moment('2020-08-27 15:40:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-08-27 15:40:00+08:00">
                <script>document.write(moment('2021-05-08 17:30:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Linux命令应用
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#ci-pin-tong-ji">词频统计</a><ul>
<li><a href="#tr-ming-ling">tr 命令</a></li>
<li><a href="#sort-ming-ling">sort 命令</a></li>
<li><a href="#uniq-ming-ling">uniq 命令</a></li>
</ul>
</li>
<li><a href="#zhi-xing-ren-wu-zhong-fang-zhi-yi-wai-duan-kai">执行任务中防止意外断开</a><ul>
<li><a href="#trap-ming-ling">trap 命令</a></li>
<li><a href="#screen-ming-ling">screen 命令</a></li>
<li><a href="#nohup-ming-ling">nohup 命令</a></li>
</ul>
</li>
<li><a href="#cha-zhao-wen-jian-bing-shan-chu">查找文件并删除</a><ul>
<li><a href="#find-ming-ling">find 命令</a></li>
<li><a href="#xargs-ming-ling">xargs 命令</a></li>
<li><a href="#rm-ming-ling">rm 命令</a></li>
</ul>
</li>
<li><a href="#tong-ji-dai-ma-xing-shu">统计代码行数</a><ul>
<li><a href="#bu-shi-yong-xargs">不使用xargs</a></li>
<li><a href="#qu-chu-kong-xing">去除空行</a></li>
</ul>
</li>
<li><a href="#da-yin-jiu-jiu-cheng-fa-biao">打印九九乘法表</a><ul>
<li><a href="#seq-ming-ling">seq 命令</a></li>
</ul>
</li>
<li><a href="#bao-liu-yan-se-ge-shi-dao-wen-jian">保留颜色格式到文件</a><ul>
<li><a href="#xiu-gai-can-shu-jie-jue">修改参数解决</a></li>
<li><a href="#script-ming-ling">script 命令</a></li>
<li><a href="#xiu-gai-pei-zhi-jie-jue">修改配置解决</a></li>
<li><a href="#qu-chu-yan-se-ge-shi">去除颜色格式</a></li>
</ul>
</li>
<li><a href="#ming-ling-xing-yin-cang-min-gan-xin-xi">命令行隐藏敏感信息</a><ul>
<li><a href="#shi-yong-ming-ling-xing-you-hao-de-gong-ju">使用命令行友好的工具</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="ci-pin-tong-ji"><a class="toclink" href="#ci-pin-tong-ji">词频统计</a></h3>
<p>读取文件，统计每个单词的使用次数，排序后输出：</p>
<div class="highlight"><pre><span></span><code>cat /etc/passwd <span class="p">|</span> tr -cs A-Za-z <span class="s1">&#39;\n&#39;</span> <span class="p">|</span> tr A-Z a-z <span class="p">|</span> sort <span class="p">|</span> uniq -c <span class="p">|</span> sort -rn <span class="p">|</span> head -n10
</code></pre></div>

<h4 id="tr-ming-ling"><a class="toclink" href="#tr-ming-ling">tr 命令</a></h4>
<p>从标准输入读取数据，经过字符串转译后（转换或删除字符），将结果输出到标准输出。  </p>
<p>命令格式：</p>
<div class="highlight"><pre><span></span><code>tr <span class="o">[</span>OPTION<span class="o">]</span>... SET1 <span class="o">[</span>SET2<span class="o">]</span>
</code></pre></div>

<p>如果是删除，则没有SET2。<br>
默认是用把SET1的字符替换为SET2里对应位置的字符。<br>
SET2长，不影响SET1的替换，SET2里后面的字符用不到。如果SET2比SET1短，SET1里后面的字符全都对应SET2的最后一个字符。  </p>
<p><code>-c, -C, --complement</code>: 反选，对不符合的字符集范围的字符进行处理。<br>
<code>-d, --delete</code>: 删除这些字符。<br>
<code>-s, --squeeze-repeats</code>: 连续重复的字符去重。比如连续多个空格只保留1个。<br>
<code>-t, --truncate-set1</code>: 如果SET1太长，先截断成和SET2一样长。这样就可以对1对1转换。  </p>
<h5 id="rot13-jia-mi-suan-fa"><a class="toclink" href="#rot13-jia-mi-suan-fa">Rot13加密算法</a></h5>
<p>Rot13（回转13位，rotate by 13 places）是一种非常简单的替换加密算法，只能加密26个英语字母。方法是：把每个字母用其后第13个字母代替。<br>
因为26个字符取一半13，正好对称，所以加密，解密是一样的：</p>
<div class="highlight"><pre><span></span><code>tr N-ZA-Mn-za-m A-Za-z
tr A-Za-z N-ZA-Mn-za-m
</code></pre></div>

<p>上面2种都可以。  </p>
<p>系统中安装了python的话，可以对Python之禅的原文操作一下，对应的文件是this.py：</p>
<div class="highlight"><pre><span></span><code>$ find / -name this.py -type f -exec cat <span class="o">{}</span> <span class="se">\;</span> <span class="p">|</span> head -n <span class="m">22</span> <span class="p">|</span> tr A-Za-z N-ZA-Mn-za-m
<span class="nv">f</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;The Zen of Python, by Tim Peters</span>

<span class="s2">Beautiful is better than ugly.</span>
<span class="s2">Explicit is better than implicit.</span>
<span class="s2">Simple is better than complex.</span>
<span class="s2">Complex is better than complicated.</span>
<span class="s2">Flat is better than nested.</span>
<span class="s2">Sparse is better than dense.</span>
<span class="s2">Readability counts.</span>
<span class="s2">Special cases aren&#39;t special enough to break the rules.</span>
<span class="s2">Although practicality beats purity.</span>
<span class="s2">Errors should never pass silently.</span>
<span class="s2">Unless explicitly silenced.</span>
<span class="s2">In the face of ambiguity, refuse the temptation to guess.</span>
<span class="s2">There should be one-- and preferably only one --obvious way to do it.</span>
<span class="s2">Although that way may not be obvious at first unless you&#39;re Dutch.</span>
<span class="s2">Now is better than never.</span>
<span class="s2">Although never is often better than *right* now.</span>
<span class="s2">If the implementation is hard to explain, it&#39;s a bad idea.</span>
<span class="s2">If the implementation is easy to explain, it may be a good idea.</span>
<span class="s2">Namespaces are one honking great idea -- let&#39;s do more of those!&quot;&quot;&quot;</span>

$ 
</code></pre></div>

<p>这里用的find命令，后面会讲到。  </p>
<h4 id="sort-ming-ling"><a class="toclink" href="#sort-ming-ling">sort 命令</a></h4>
<p>对文本内容以行为单位进行排序。  </p>
<p>默认都是按字符排序的，也有其他排序规则。<br>
<code>-M, --month-sort</code>: 对月份排序，(unknown) &lt; 'JAN' &lt; ... &lt; 'DEC'。<br>
<code>-h, --human-numeric-sort</code>: 对容量单位排序，比如：2K，1G这种。<br>
<code>-n, --numeric-sort</code>: 对数字排序。  </p>
<h4 id="uniq-ming-ling"><a class="toclink" href="#uniq-ming-ling">uniq 命令</a></h4>
<p>检查或删除重复出现的行。<br>
重复出现必须相邻，也就是连续出现，所以一般与 sort 命令结合使用。  </p>
<p><code>-c, --count</code>: 在每行开头显示重复出现的次数。  </p>
<h3 id="zhi-xing-ren-wu-zhong-fang-zhi-yi-wai-duan-kai"><a class="toclink" href="#zhi-xing-ren-wu-zhong-fang-zhi-yi-wai-duan-kai">执行任务中防止意外断开</a></h3>
<p>执行耗时很长的任务时，如果中途断开连接，会导致任务中断结束。<br>
<strong>原因分析：</strong>系统会分配给登录用户一个终端（Session）。在这个终端运行的所有程序，都是当前终端的子进程。系统信号中的SIGHUP信号，在用户终端连接(正常或非正常)结束时，会通知当前终端下的各个作业（包括前台和后台），之后它们与控制终端不再关联。SIGHUP信号的默认操作是终止进程。<br>
<em>常用的wget命令，默认就会改变SIGHUP信号的默认操作，所以中途断开时不会中断下载。</em><br>
<em>此外，SIGHUP还有一个作用。上面的作用是通知进程与终端脱离关系。而对于与终端脱离关系的守护进程，这个信号的作用是通知它重新读取配置文件。</em>  </p>
<p>下面的trap命令不是推荐的解决办法，主要为了说明和验证。后面的两个命令是推荐的解决办法。  </p>
<h4 id="trap-ming-ling"><a class="toclink" href="#trap-ming-ling">trap 命令</a></h4>
<p>使用如下命令查看帮助：</p>
<div class="highlight"><pre><span></span><code><span class="nb">help</span> <span class="nb">trap</span>
</code></pre></div>

<p>查看所以信号的编号和名称：</p>
<div class="highlight"><pre><span></span><code><span class="nb">trap</span> -l
</code></pre></div>

<p>用法一，接收到对应的信号时执行命令：</p>
<div class="highlight"><pre><span></span><code><span class="nb">trap</span> <span class="s2">&quot;commands&quot;</span> signal-list
</code></pre></div>

<p>用法二，只接收信号，不指定命令：</p>
<div class="highlight"><pre><span></span><code><span class="nb">trap</span> signal-list 
</code></pre></div>

<p>未指定命令，就是执行默认操作，默认操作是结束进程。  </p>
<p>用法三，指定一个空字符串作为命令：</p>
<div class="highlight"><pre><span></span><code><span class="nb">trap</span> <span class="s1">&#39;&#39;</span> signal-list
</code></pre></div>

<p>指定空命令就是忽略该信号。  </p>
<p>查看当前的信号处理命令：</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">trap</span> -p
<span class="nb">trap</span> -- <span class="s1">&#39;&#39;</span> SIGTSTP
<span class="nb">trap</span> -- <span class="s1">&#39;&#39;</span> SIGTTIN
<span class="nb">trap</span> -- <span class="s1">&#39;&#39;</span> SIGTTOU
$ 
</code></pre></div>

<p>这里是在当前shell下执行的，表示shell会对上面3个信号忽略。  </p>
<h5 id="bu-huo-jiao-ben-de-xin-hao"><a class="toclink" href="#bu-huo-jiao-ben-de-xin-hao">捕获脚本的信号</a></h5>
<p>虽然捕获HUP信号就能防止因终端退出而导致的程序终止。但这不是一个通用和推荐的方法，这里是为了验证和演示效果。<br>
下面是一个简单的用于验证的脚本：</p>
<div class="highlight"><pre><span></span><code>$ cat heartbeat.sh 
<span class="c1">#!/bin/bash</span>
<span class="nb">trap</span> <span class="s2">&quot;echo 收到信号:HUP&quot;</span> SIGHUP
<span class="nb">trap</span> -p
<span class="k">for</span> i <span class="k">in</span> <span class="o">{</span><span class="m">1</span>..300<span class="o">}</span>
<span class="k">do</span>
    <span class="nb">echo</span> <span class="nv">$i</span>
    sleep <span class="m">1</span>
<span class="k">done</span>
$ 
</code></pre></div>

<p>现在这个脚本收到SIGHUP信号，只会打印一行消息，不会再终止脚本运行了。  </p>
<p>用下面的命令运行脚本：</p>
<div class="highlight"><pre><span></span><code>./heartbeat.sh &gt; heartbeat.txt
</code></pre></div>

<p>另外开一个终端，查看文件内容的刷新：</p>
<div class="highlight"><pre><span></span><code>tail -f heartbeat.txt
</code></pre></div>

<p>之后断开运行脚本的那个终端，就可以看到捕获信号而打印的消息，而脚本可以继续运行。<br>
终端断开后，再连回去，已经不是之前的那个终端了，所以返回断开重连是不会再收到信号了。<br>
可以用命令手动发信号：</p>
<div class="highlight"><pre><span></span><code>ps -ef <span class="p">|</span> grep heartbeat
<span class="nb">kill</span> -HUP PID
</code></pre></div>

<p>到这里再用ps命令关注一下脚本的父进程，通过父进程的PID。一开始父进程是当前终端，一旦终端退出后，脚本的父进程就变成了PID为1的系统进程。  </p>
<p>现在要终止脚本，可以用kill命令发送SIGTERM(15)信号，或者不指定信号就是这个默认信号。<br>
或者用killall命令，不用再去查PID了：</p>
<div class="highlight"><pre><span></span><code>killall heartbeat.sh
</code></pre></div>

<p>或者放着不管也行，脚本没写死循环，300秒后就跑完了。  </p>
<h4 id="screen-ming-ling"><a class="toclink" href="#screen-ming-ling">screen 命令</a></h4>
<p>scree的作用就是开启screen会话，在会话下执行程序。断开终端不会终止screen会话，会话下的程序也就不会有任何影响。<br>
另外，还有个好处。重连回来之后，可以回到之前的screen会话里。继续可以在终端上收到消息，这是这个解决方法的优势。  </p>
<p>使用screen需要先安装，yum一下就好。这里重点讲只使用一个会话时的用法。  </p>
<p>启动会话，用-S（大写）参数为会话命名：</p>
<div class="highlight"><pre><span></span><code>screen
screen -S NAME
</code></pre></div>

<p>使用多个会话时，方便选择。  </p>
<p>分离会话，返回shell：</p>
<div class="highlight"><pre><span></span><code>screen -d
screen -d NAME
</code></pre></div>

<p>命令之后会多半会占用前台，所以此时打不了命令。可以用快捷键 Ctrl a+d。<br>
或者简单粗暴，直接断开连接。再连上的时候，是在shell中。  </p>
<p>重连会话：</p>
<div class="highlight"><pre><span></span><code>screen -r
screen -r NANE
</code></pre></div>

<p>如果已经有多个会话，需要指定名字或会话ID。  </p>
<p>查看会话：</p>
<div class="highlight"><pre><span></span><code>$ screen -ls
There are screens on:
        <span class="m">5923</span>.pts-0.Playhost     <span class="o">(</span>Attached<span class="o">)</span>
        <span class="m">5902</span>.pts-0.Playhost     <span class="o">(</span>Detached<span class="o">)</span>
        <span class="m">5886</span>.pts-0.Playhost     <span class="o">(</span>Detached<span class="o">)</span>
        <span class="m">5871</span>.pts-0.Playhost     <span class="o">(</span>Detached<span class="o">)</span>
<span class="m">4</span> Sockets <span class="k">in</span> /var/run/screen/S-root.

$  
</code></pre></div>

<p>这里有4个会话，(Attached)是当前所在的会话，(Detached)是其他会话。如果在shell中，所有的都是(Detached)。<br>
也可能有多个(Attached)，那就是进入了多个screen，多个screen的使用不深入研究了。  </p>
<p>关闭会话：在会话中 exit。退出后这个会话就没有了，会话下的程序也都会收到信号然后终止。  </p>
<h4 id="nohup-ming-ling"><a class="toclink" href="#nohup-ming-ling">nohup 命令</a></h4>
<p>在执行的命令前加上nohup，就帮我们捕获并忽略HUP信号。  </p>
<p>在上面的脚本中有一句<code>trap -p</code>，会打印捕获的信号和处理命令。使用nohup执行脚本：</p>
<div class="highlight"><pre><span></span><code>$ nohup ./heartbeat.sh &gt; heartbeat.txt 
nohup: 忽略输入重定向错误到标准输出端
</code></pre></div>

<p>之后再去查看输出的文件，里面<code>trap -p</code>输出的那行就是：</p>
<div class="highlight"><pre><span></span><code><span class="nb">trap</span> -- <span class="s1">&#39;&#39;</span> SIGHUP
</code></pre></div>

<p>所以帮我们把这个信号忽略了。并且还会忽略程序中对SIGHUP信号的处理。<br>
<em>脚本第一行手写的HUP信号捕获的语句还在，但是用了nohup就会无效。如果是脚本中多次出现信号捕获的语句，最新的信号处理命令会覆盖之前的设置。</em>  </p>
<p>用nohup还有个缺点，无法在屏幕上看到输出了。如果不用重定向，屏幕上也不会有输出，而是会重定向到一个默认的文件nohup.out。<br>
所以，这并不是一个为了防止终端<strong>意外</strong>断开的命令。用了一会就会重定向到终端的输出，体验不是很好。好处是不用安装直接能用。<br>
使用的场景一般是启动了程序后，原本就是要断开终端。比如要启动一个程序让它像服务一样一直挂在后台跑着，那只要一行命令就搞定了，比写个service方便多了（和service比无法中断后自动重启）。<br>
另外，一般在用的时候还要在后面加上&amp;。具体效果往下看。  </p>
<h5 id="nohup-he"><a class="toclink" href="#nohup-he">nohup 和 &amp;</a></h5>
<p>nohup命令一般在使用时，会在最后再加上&amp;。&amp;的效果是让程序在后台运行。<br>
用这个办法执行的命令会在后台运行，此时前端可以继续做其他的操作。再断开shell也不会影响程序运行：</p>
<div class="highlight"><pre><span></span><code>nohup COMMAND <span class="p">&amp;</span>
</code></pre></div>

<p><strong>注意：</strong>执行命令后需要再按一下按键回到shell之后才算成功，此时才能放心退出或断开。  </p>
<p>用nohup命令，让任务可以不挂断运行，但是依然是在前台运行，占用着终端。如果忘记最后的&amp;，可以试试下面的 Ctrl + z。<br>
在命令的最后加上&amp;符号，表示命令在后台执行。虽然是后台运行，但是依然和父进程的终端绑定，终端退出后任务还是会结束。  </p>
<h5 id="qi-ta-ren-wu-diao-du-ming-ling"><a class="toclink" href="#qi-ta-ren-wu-diao-du-ming-ling">其他任务调度命令</a></h5>
<p>后台运行的任务，可以用 jobs 命令来查看。可以看到任务的jobnun，其他命令里可以用%jobnum指定任务:</p>
<div class="highlight"><pre><span></span><code>$ sleep <span class="m">60</span> <span class="p">&amp;</span>
<span class="o">[</span><span class="m">1</span><span class="o">]</span> <span class="m">14649</span>
$ sleep <span class="m">60</span> <span class="p">&amp;</span>
<span class="o">[</span><span class="m">2</span><span class="o">]</span> <span class="m">14651</span>
$ sleep <span class="m">60</span> <span class="p">&amp;</span>
<span class="o">[</span><span class="m">3</span><span class="o">]</span> <span class="m">14652</span>
$ <span class="nb">jobs</span>
<span class="o">[</span><span class="m">1</span><span class="o">]</span>   运行中               sleep <span class="m">60</span> <span class="p">&amp;</span>
<span class="o">[</span><span class="m">2</span><span class="o">]</span>-  运行中               sleep <span class="m">60</span> <span class="p">&amp;</span>
<span class="o">[</span><span class="m">3</span><span class="o">]</span>+  运行中               sleep <span class="m">60</span> <span class="p">&amp;</span>
$ 
</code></pre></div>

<p>执行命令会，会打印任务的PID。这里开了3个任务，执行jobs后，看到任务的标号1~3。  </p>
<p>用fg命令，可以把后台的任务调至前台继续运行。<br>
快捷键 Ctrl + z，将前台的命令放到后台，并且暂停。后面用bg命令再启动。<br>
用bg命令，将一个在后台暂停的命令变成在后台继续运行。<br>
上面的这些任务调度，只能在当前的shell中维持，一旦断开或退出就无法再管理了。再连上来后，只能用ps和kill来查看和关闭进程。  </p>
<h3 id="cha-zhao-wen-jian-bing-shan-chu"><a class="toclink" href="#cha-zhao-wen-jian-bing-shan-chu">查找文件并删除</a></h3>
<p>命令如下：</p>
<div class="highlight"><pre><span></span><code>$ touch test<span class="o">{</span><span class="m">1</span>..3<span class="o">}</span>.del
$ find . -name <span class="s1">&#39;test?.del&#39;</span> -type f -print0 <span class="p">|</span> xargs -0 rm -v         
已删除<span class="s2">&quot;./test1.del&quot;</span>
已删除<span class="s2">&quot;./test2.del&quot;</span>
已删除<span class="s2">&quot;./test3.del&quot;</span>
$ 
</code></pre></div>

<p>rm 命令的 -v 参数会打印正在进行的操作，否则命令执行后是没有反馈的。在脚本中可以删除。<br>
find 命令的 -print0 和 xargs 命令的 -0 都是为了能处理文件名中的特殊字符和空格。所以最好都加上防止有坑。  </p>
<p>其实也可以不用xargs：</p>
<div class="highlight"><pre><span></span><code>$ find . -name <span class="s1">&#39;test?.del&#39;</span> -type f -exec rm -v <span class="o">{}</span> <span class="se">\;</span>
</code></pre></div>

<h4 id="find-ming-ling"><a class="toclink" href="#find-ming-ling">find 命令</a></h4>
<p>可以在指定目录下查找文件，也包括目录（一切皆文件）。  </p>
<p>-print0: 名称将以空字符结尾，并且保留空格和特殊字符。这个在将结果传递给别的命令的时候需要加上。<br>
-type C: 指定文件类型。d-目录,f-一般文件,l-符号链接,s-socket，另外还有些其他我不理解的类型。<br>
-name: 匹配文件名。<br>
-iname: 忽略大小写匹配文件名。<br>
-not: 反选，让find返回所有与搜索模式不匹配的文件。<br>
-mtime -n/+n: 按文件更改时间查找，-n表示n天以内，+n表示n天以前。<code>-mtime -1</code>把1天内有修改过的文件找出来，可以用这个做文件的增量备份。  </p>
<h5 id="pei-he-grep-shi-yong"><a class="toclink" href="#pei-he-grep-shi-yong">配合grep使用</a></h5>
<p>find命令的参数还有很多，比如下面的这个：<br>
-regex, -iregex: 用正则匹配文件名，i开头的是忽略大小写。  </p>
<p>find命令的基本形式是输出匹配的文件，每行一个。所以要获取最终的结果也不必拘泥于find命令，可以用管道符交给grep再加工。grep命令有方便的反选（-v）选项，比如过滤掉隐藏文件。  </p>
<p><strong>其他问题</strong><br>
如果遇到下面-exec这样的需求，可以用后面的xargs来替代。<br>
如果是遇到-print0这样的需求，可以试着将'\n'替换为'\0'：</p>
<div class="highlight"><pre><span></span><code>$ find /etc/passwd -print0 <span class="p">|</span> od -b
<span class="m">0000000</span> <span class="m">057</span> <span class="m">145</span> <span class="m">164</span> <span class="m">143</span> <span class="m">057</span> <span class="m">160</span> <span class="m">141</span> <span class="m">163</span> <span class="m">163</span> <span class="m">167</span> <span class="m">144</span> <span class="m">000</span>
<span class="m">0000014</span>
$ find /etc/passwd <span class="p">|</span> tr <span class="s1">&#39;\n&#39;</span> <span class="s1">&#39;\0&#39;</span> <span class="p">|</span> od -b
<span class="m">0000000</span> <span class="m">057</span> <span class="m">145</span> <span class="m">164</span> <span class="m">143</span> <span class="m">057</span> <span class="m">160</span> <span class="m">141</span> <span class="m">163</span> <span class="m">163</span> <span class="m">167</span> <span class="m">144</span> <span class="m">000</span>
<span class="m">0000014</span>
$ 
</code></pre></div>

<h5 id="zhi-xing-ming-ling-cao-zuo"><a class="toclink" href="#zhi-xing-ming-ling-cao-zuo">执行命令操作</a></h5>
<p>其实可以用 -exec 来对找到的文件执行命令操作，不过语法要注意：</p>
<div class="highlight"><pre><span></span><code>-exec <span class="nb">command</span> <span class="o">{}</span> <span class="se">\;</span>
</code></pre></div>

<p>大括号和反斜杠之间要有空格，并且由于反斜杠表示这行，最后还得紧跟一个分号。  </p>
<div class="highlight"><pre><span></span><code>$ touch test<span class="o">{</span><span class="m">1</span>..3<span class="o">}</span>.del
$ find . -name <span class="s1">&#39;test?.del&#39;</span> -type f -exec ls <span class="o">{}</span> <span class="se">\;</span>    
./test1.del
./test2.del
./test3.del
$ 
</code></pre></div>

<p>所以如果是find命令的话，需不要xargs来配合。  </p>
<h4 id="xargs-ming-ling"><a class="toclink" href="#xargs-ming-ling">xargs 命令</a></h4>
<p>通常可以用管道将多个命令连接起来：</p>
<div class="highlight"><pre><span></span><code>command1 <span class="p">|</span> command2
</code></pre></div>

<p>但是也有些命令无法从标准输入接收数据，比如ls，rm。  </p>
<p>用xargs命令，从标准输入接收数据，然后生成单行的命令行参数传递给下一个命令：</p>
<div class="highlight"><pre><span></span><code>command1 <span class="p">|</span> xargs command2
</code></pre></div>

<p>如果没有为xargs指定命令，默认使用echo。xargs始终生成单行的输出，多行会转成一行：</p>
<div class="highlight"><pre><span></span><code>$ seq <span class="m">5</span> <span class="p">|</span> xargs
<span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span>
$ 
</code></pre></div>

<h5 id="da-yin-jie-guo-bing-que-ren"><a class="toclink" href="#da-yin-jie-guo-bing-que-ren">打印结果并确认</a></h5>
<p>使用-p选项之后xargs会先打印出转换后的命令，并等待用户确认是否要执行：</p>
<div class="highlight"><pre><span></span><code>$ seq <span class="m">5</span> <span class="p">|</span> xargs -p
<span class="nb">echo</span> <span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span> ?...
$ seq <span class="m">5</span> <span class="p">|</span> xargs -p
<span class="nb">echo</span> <span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span> ?...y
<span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span>
$ 
</code></pre></div>

<p>这里没有提供命令，使用了默认命令echo。<br>
确认执行需要输入 y/Y，否则就放弃。<br>
利用这个选项可以帮助我们确认命令是否写正确了。  </p>
<h5 id="zhi-ding-ti-huan-zi-fu-chuan"><a class="toclink" href="#zhi-ding-ti-huan-zi-fu-chuan">指定替换字符串</a></h5>
<p>默认是将结果一下子全部添加到命令的最后的。使用-I参数可以指定一个字符字符串来构建命令。  </p>
<p>每一个参数调用一次命令，并且可以指定参数位置：</p>
<div class="highlight"><pre><span></span><code>$ seq <span class="m">5</span> <span class="p">|</span> xargs -p <span class="nb">echo</span>
<span class="nb">echo</span> <span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span> ?...y
<span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span>
$ seq <span class="m">5</span> <span class="p">|</span> xargs -p -I % <span class="nb">echo</span> %
<span class="nb">echo</span> <span class="m">1</span> ?...y
<span class="m">1</span>
<span class="nb">echo</span> <span class="m">2</span> ?...y
<span class="m">2</span>
<span class="nb">echo</span> <span class="m">3</span> ?...y
<span class="m">3</span>
<span class="nb">echo</span> <span class="m">4</span> ?...y
<span class="m">4</span>
<span class="nb">echo</span> <span class="m">5</span> ?...y
<span class="m">5</span>
$ 
</code></pre></div>

<p>因为有替换字符串，参数可以出现在任意位置，可以不在最后了。</p>
<p>多个命令一起使用：</p>
<div class="highlight"><pre><span></span><code>$ cat test.del 
test1.del
test2.del
test3.del
$ cat test.del <span class="p">|</span> xargs -I <span class="o">{}</span> sh -c <span class="s1">&#39;ls {}; ls -l {}&#39;</span>
test1.del
-rw-r--r--. <span class="m">1</span> root root <span class="m">0</span> 8月  <span class="m">28</span> <span class="m">16</span>:22 test1.del
test2.del
-rw-r--r--. <span class="m">1</span> root root <span class="m">0</span> 8月  <span class="m">28</span> <span class="m">16</span>:22 test2.del
test3.del
-rw-r--r--. <span class="m">1</span> root root <span class="m">0</span> 8月  <span class="m">28</span> <span class="m">16</span>:22 test3.del
$ 
</code></pre></div>

<p>这里先写了一个文件，然后用cat逐行输出了文件名。<br>
xargs设置了{}为替换字符串，对每一行调用了一次指定的命令，命令中引用了2次参数。<br>
为了能一次执行两条命令，这里用<code>sh -c</code>启动了一个子shell，在里面执行一组命令。  </p>
<h4 id="rm-ming-ling"><a class="toclink" href="#rm-ming-ling">rm 命令</a></h4>
<p>平时用的很多，但是还是有些要注意的。平时删文件的时候默认是有确认的，这是因为shell里做了alias：</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">alias</span> rm
<span class="nb">alias</span> <span class="nv">rm</span><span class="o">=</span><span class="s1">&#39;rm -i&#39;</span>
$ 
</code></pre></div>

<p>在xargs调用rm的时候，alias是不生效的，所以这时候删文件是没有确认的。  </p>
<h3 id="tong-ji-dai-ma-xing-shu"><a class="toclink" href="#tong-ji-dai-ma-xing-shu">统计代码行数</a></h3>
<p>这里的统计是统计行数，并且是不去除空行的。<br>
下面是推荐使用的命令：</p>
<div class="highlight"><pre><span></span><code>$ find . -type f <span class="p">|</span> xargs wc -l
 <span class="m">4</span> ./test2.txt
 <span class="m">4</span> ./test1.txt
 <span class="m">4</span> ./testb/test3.txt
 <span class="m">4</span> ./testc/testc2/test5.txt
 <span class="m">4</span> ./testc/test4.txt
<span class="m">20</span> total
$ 
</code></pre></div>

<p>先用find命令筛选文件，然后管道符交给xargs和wc处理。<br>
可以统计每个文件的行数，以及总的行数。  </p>
<h4 id="bu-shi-yong-xargs"><a class="toclink" href="#bu-shi-yong-xargs">不使用xargs</a></h4>
<p>find命令自带的-exec参数似乎也能处理，不需要借助xargs。但实际效果有差别。<br>
如果要使用find的-exec的话，是无法统计总的行数的：</p>
<div class="highlight"><pre><span></span><code>$ find . -type f -exec wc -l <span class="o">{}</span> <span class="se">\;</span>
<span class="m">4</span> ./test2.txt
<span class="m">4</span> ./test1.txt
<span class="m">4</span> ./testb/test3.txt
<span class="m">4</span> ./testc/testc2/test5.txt
<span class="m">4</span> ./testc/test4.txt
$ 
</code></pre></div>

<p>原因分析，这里相当于一个个取文件名交给wc处理，类似下面第二种命令执行方式：</p>
<div class="highlight"><pre><span></span><code>$ wc -l test1.txt test2.txt
 <span class="m">4</span> test1.txt
 <span class="m">4</span> test2.txt
 <span class="m">8</span> total
$ wc -l test1.txt<span class="p">;</span> wc -l test2.txt
<span class="m">4</span> test1.txt
<span class="m">4</span> test2.txt
$ 
</code></pre></div>

<p>上面第一种是类似xargs处理文件名的方式，第二种是find的-exec处理文件名的方式。  </p>
<p>如果再加上awk处理一下，也能统计总数：</p>
<div class="highlight"><pre><span></span><code>$ find . -type f -exec wc -l <span class="o">{}</span> <span class="se">\;</span><span class="p">|</span> awk <span class="s1">&#39;{print $1,$2;a+=$1}END{print a,&quot;total&quot;}&#39;</span>
<span class="m">4</span> ./test2.txt
<span class="m">4</span> ./test1.txt
<span class="m">4</span> ./testb/test3.txt
<span class="m">4</span> ./testc/testc2/test5.txt
<span class="m">4</span> ./testc/test4.txt
<span class="m">20</span> total
$ 
</code></pre></div>

<p>格式问题可以用awk的printf打印，这里就不纠结格式。<br>
还是使用最开始推荐的用法。  </p>
<h4 id="qu-chu-kong-xing"><a class="toclink" href="#qu-chu-kong-xing">去除空行</a></h4>
<p>要去除空行统计，暂时只能统计总数。<br>
过滤掉空行的方式如下：</p>
<div class="highlight"><pre><span></span><code>grep -v <span class="s1">&#39;^[[:space:]]*$&#39;</span>
</code></pre></div>

<p>这里的做法就是把非空行逐行打印出来管道传给wc命令来统计行数：</p>
<div class="highlight"><pre><span></span><code>$ find . -type f <span class="p">|</span> xargs grep -v <span class="s1">&#39;^[[:space:]]*$&#39;</span> <span class="p">|</span> wc -l
<span class="m">15</span>
$ 
</code></pre></div>

<p>这里的做法很粗糙，没法像上面一样先逐个文件统计，然后再聚合。只能凑合使用。<br>
当然，写个脚本，通过循环这并不难实现。这里主要关注命令使用，脚本就不考虑了。  </p>
<h3 id="da-yin-jiu-jiu-cheng-fa-biao"><a class="toclink" href="#da-yin-jiu-jiu-cheng-fa-biao">打印九九乘法表</a></h3>
<p>这里直接给出命令和效果：</p>
<div class="highlight"><pre><span></span><code>$ seq <span class="m">9</span> <span class="p">|</span> sed <span class="s1">&#39;H;g&#39;</span> <span class="p">|</span> awk -v <span class="nv">RS</span><span class="o">=</span><span class="s1">&#39;&#39;</span> <span class="s1">&#39;{for(i=1;i&lt;=NF;i++)printf(&quot;%dx%d=%d%s&quot;, i, NR, i*NR, i==NR?&quot;\n&quot;:&quot;\t&quot;)}&#39;</span>
<span class="nv">1x1</span><span class="o">=</span><span class="m">1</span>
<span class="nv">1x2</span><span class="o">=</span><span class="m">2</span>   <span class="nv">2x2</span><span class="o">=</span><span class="m">4</span>
<span class="nv">1x3</span><span class="o">=</span><span class="m">3</span>   <span class="nv">2x3</span><span class="o">=</span><span class="m">6</span>   <span class="nv">3x3</span><span class="o">=</span><span class="m">9</span>
<span class="nv">1x4</span><span class="o">=</span><span class="m">4</span>   <span class="nv">2x4</span><span class="o">=</span><span class="m">8</span>   <span class="nv">3x4</span><span class="o">=</span><span class="m">12</span>  <span class="nv">4x4</span><span class="o">=</span><span class="m">16</span>
<span class="nv">1x5</span><span class="o">=</span><span class="m">5</span>   <span class="nv">2x5</span><span class="o">=</span><span class="m">10</span>  <span class="nv">3x5</span><span class="o">=</span><span class="m">15</span>  <span class="nv">4x5</span><span class="o">=</span><span class="m">20</span>  <span class="nv">5x5</span><span class="o">=</span><span class="m">25</span>
<span class="nv">1x6</span><span class="o">=</span><span class="m">6</span>   <span class="nv">2x6</span><span class="o">=</span><span class="m">12</span>  <span class="nv">3x6</span><span class="o">=</span><span class="m">18</span>  <span class="nv">4x6</span><span class="o">=</span><span class="m">24</span>  <span class="nv">5x6</span><span class="o">=</span><span class="m">30</span>  <span class="nv">6x6</span><span class="o">=</span><span class="m">36</span>
<span class="nv">1x7</span><span class="o">=</span><span class="m">7</span>   <span class="nv">2x7</span><span class="o">=</span><span class="m">14</span>  <span class="nv">3x7</span><span class="o">=</span><span class="m">21</span>  <span class="nv">4x7</span><span class="o">=</span><span class="m">28</span>  <span class="nv">5x7</span><span class="o">=</span><span class="m">35</span>  <span class="nv">6x7</span><span class="o">=</span><span class="m">42</span>  <span class="nv">7x7</span><span class="o">=</span><span class="m">49</span>
<span class="nv">1x8</span><span class="o">=</span><span class="m">8</span>   <span class="nv">2x8</span><span class="o">=</span><span class="m">16</span>  <span class="nv">3x8</span><span class="o">=</span><span class="m">24</span>  <span class="nv">4x8</span><span class="o">=</span><span class="m">32</span>  <span class="nv">5x8</span><span class="o">=</span><span class="m">40</span>  <span class="nv">6x8</span><span class="o">=</span><span class="m">48</span>  <span class="nv">7x8</span><span class="o">=</span><span class="m">56</span>  <span class="nv">8x8</span><span class="o">=</span><span class="m">64</span>
<span class="nv">1x9</span><span class="o">=</span><span class="m">9</span>   <span class="nv">2x9</span><span class="o">=</span><span class="m">18</span>  <span class="nv">3x9</span><span class="o">=</span><span class="m">27</span>  <span class="nv">4x9</span><span class="o">=</span><span class="m">36</span>  <span class="nv">5x9</span><span class="o">=</span><span class="m">45</span>  <span class="nv">6x9</span><span class="o">=</span><span class="m">54</span>  <span class="nv">7x9</span><span class="o">=</span><span class="m">63</span>  <span class="nv">8x9</span><span class="o">=</span><span class="m">72</span>  <span class="nv">9x9</span><span class="o">=</span><span class="m">81</span>
$ 
</code></pre></div>

<p>sed 和 awk 命令太复杂了，这里的用法Hold不住。先把seq命令记下。  </p>
<h4 id="seq-ming-ling"><a class="toclink" href="#seq-ming-ling">seq 命令</a></h4>
<p>seq命令可以输出连续的数字，或者输出固定间隔的数字，或者输出指定格式的数字。  </p>
<p>一个参数：</p>
<div class="highlight"><pre><span></span><code>$ seq <span class="m">5</span>
<span class="m">1</span>
<span class="m">2</span>
<span class="m">3</span>
<span class="m">4</span>
<span class="m">5</span>
</code></pre></div>

<p>这种输出用大括号扩展似乎做不到，前面会多一行，还得再去掉：</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> -e <span class="s2">&quot;\n&quot;</span><span class="o">{</span><span class="m">1</span>..3<span class="o">}</span>

<span class="m">1</span> 
<span class="m">2</span> 
<span class="m">3</span>
$ <span class="nb">echo</span> -e <span class="s2">&quot;\n&quot;</span><span class="o">{</span><span class="m">1</span>..3<span class="o">}</span> <span class="p">|</span> sed -n <span class="s1">&#39;1!p&#39;</span>
<span class="m">1</span> 
<span class="m">2</span> 
<span class="m">3</span>
$ 
</code></pre></div>

<p>用-s指定空格分隔：</p>
<div class="highlight"><pre><span></span><code>$ seq -s <span class="s1">&#39; &#39;</span> <span class="m">5</span>
<span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span>
$ <span class="nb">echo</span> <span class="o">{</span><span class="m">1</span>..5<span class="o">}</span>
<span class="m">1</span> <span class="m">2</span> <span class="m">3</span> <span class="m">4</span> <span class="m">5</span>
$ 
</code></pre></div>

<p>两个参数，指定首尾的数字：</p>
<div class="highlight"><pre><span></span><code>$ seq -s <span class="s1">&#39; &#39;</span> <span class="m">3</span> <span class="m">10</span>
<span class="m">3</span> <span class="m">4</span> <span class="m">5</span> <span class="m">6</span> <span class="m">7</span> <span class="m">8</span> <span class="m">9</span> <span class="m">10</span>
$ 
</code></pre></div>

<p>三个参数，起始、间隔、结尾：</p>
<div class="highlight"><pre><span></span><code>$ seq -s <span class="s1">&#39; &#39;</span> <span class="m">10</span> <span class="m">11</span> <span class="m">100</span>
<span class="m">10</span> <span class="m">21</span> <span class="m">32</span> <span class="m">43</span> <span class="m">54</span> <span class="m">65</span> <span class="m">76</span> <span class="m">87</span> <span class="m">98</span>
$ 
</code></pre></div>

<p>用-w参数，定宽输出，前面补0，以最大的数的宽度为依据：</p>
<div class="highlight"><pre><span></span><code>$ seq -w <span class="m">8</span> <span class="m">12</span>
<span class="m">08</span>
<span class="m">09</span>
<span class="m">10</span>
<span class="m">11</span>
<span class="m">12</span>
$ seq -w <span class="m">1</span> <span class="m">95</span> <span class="m">200</span>
<span class="m">001</span>
<span class="m">096</span>
<span class="m">191</span>
$ 
</code></pre></div>

<p>如果想自己决定最大宽度，就用下更强大的-f。  </p>
<p>自定义格式，用-f，默认格式是'%g'，这里的%g表示整数，还有%f是浮点数,%e科学计数：</p>
<div class="highlight"><pre><span></span><code>$ seq -f <span class="s1">&#39;%3g&#39;</span> <span class="m">8</span> <span class="m">12</span>  
  <span class="m">8</span>
  <span class="m">9</span>
 <span class="m">10</span>
 <span class="m">11</span>
 <span class="m">12</span>
$ seq -f <span class="s1">&#39;%03g&#39;</span> <span class="m">8</span> <span class="m">12</span>
<span class="m">008</span>
<span class="m">009</span>
<span class="m">010</span>
<span class="m">011</span>
<span class="m">012</span>
$ 
</code></pre></div>

<p>用了-w和-f不能同时使用，毕竟-f就是高级的-w。  </p>
<p>还可以在前后加字符：</p>
<div class="highlight"><pre><span></span><code>$ seq -f <span class="s1">&#39;file%03g.txt&#39;</span> -s <span class="s1">&#39; &#39;</span> <span class="m">8</span> <span class="m">12</span>
file008.txt file009.txt file010.txt file011.txt file012.txt
$ <span class="nb">echo</span> file<span class="o">{</span><span class="m">008</span>..012<span class="o">}</span>.txt
file008.txt file009.txt file010.txt file011.txt file012.txt
$ 
</code></pre></div>

<p>不过，这种时候还是用大括号扩展比较方便，好理解。  </p>
<h3 id="bao-liu-yan-se-ge-shi-dao-wen-jian"><a class="toclink" href="#bao-liu-yan-se-ge-shi-dao-wen-jian">保留颜色格式到文件</a></h3>
<p>有些命令输出的内容是带颜色的，比如ls、grep。这里额外提一下，默认是没颜色的，只是系统里用别名自动加了参数：</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">alias</span> ls grep
<span class="nb">alias</span> <span class="nv">ls</span><span class="o">=</span><span class="s1">&#39;ls --color=auto&#39;</span>
<span class="nb">alias</span> <span class="nv">grep</span><span class="o">=</span><span class="s1">&#39;grep --color=auto&#39;</span>
$
</code></pre></div>

<p>还有一些工具输出也有颜色便于查看，比如ansible：</p>
<div class="highlight"><pre><span></span><code>$ ansible localhost -m debug
localhost <span class="p">|</span> <span class="nv">SUCCESS</span> <span class="o">=</span>&gt; <span class="o">{</span>
    <span class="s2">&quot;msg&quot;</span>: <span class="s2">&quot;Hello world!&quot;</span>
<span class="o">}</span>
$ 
</code></pre></div>

<p><em>这里显示不出颜色。</em>  </p>
<p>如果把记录重定向到文件，之后再看就看不到颜色了：</p>
<div class="highlight"><pre><span></span><code>$ ansible localhost -m debug &gt; test1
$ cat test1
</code></pre></div>

<p>大致的原因是，系统会自动判断输出的文件描述符是否是一个终端设备，只有终端设备才会加上颜色。<br>
可以用下面的命令查看当前使用的终端：</p>
<div class="highlight"><pre><span></span><code>$ who
root     pts/0        <span class="m">2020</span>-10-14 <span class="m">10</span>:51 <span class="o">(</span><span class="m">192</span>.168.163.1<span class="o">)</span>
$ tty
/dev/pts/0
$ 
</code></pre></div>

<h4 id="xiu-gai-can-shu-jie-jue"><a class="toclink" href="#xiu-gai-can-shu-jie-jue">修改参数解决</a></h4>
<p>像ls、grep这些命令是可以用个参数解决的：</p>
<div class="highlight"><pre><span></span><code>$ ls --color<span class="o">=</span>always &gt; test1
$ cat test1
</code></pre></div>

<p>使用<code>--color=always</code>参数，就可以把格式一起输入到文件中了。<br>
另外，有一些命令本身是没有参数支持的。这就需要用到下面的命令。  </p>
<h4 id="script-ming-ling"><a class="toclink" href="#script-ming-ling">script 命令</a></h4>
<p>script 的作用是录屏，把输出到终端的记录记录到文件。所以可以用来录制会话，也可以用来做安全审计，但是这里不关心这些。  </p>
<p>这里解决将颜色格式一并保存到文件的问题。可以在脚本中这样用：</p>
<div class="highlight"><pre><span></span><code>script
<span class="k">do</span> something here
<span class="nb">exit</span>
</code></pre></div>

<p>用script开始录制，再以exit结束录制。结束之前，所有的输出都会保存一份到文件。默认保存到typescript文件，没有就创建，有就覆盖。  </p>
<h5 id="zhu-yi-shi-xiang"><a class="toclink" href="#zhu-yi-shi-xiang">注意事项</a></h5>
<p>命令script会开启一个新的终端，期间的命令都不会被history记录。<br>
在命令行直接执行script命令要注意：</p>
<div class="highlight"><pre><span></span><code>$ PS1=&#39;\$(OUT) &#39;
$(OUT) script
Script started, file is typescript
$ exit
exit
Script done, file is typescript
$(OUT)
</code></pre></div>

<p>执行script命令后，就进入了一个新的进程，终端也是新的。上面的例子里可看到命令提示符的变化。<br>
再执行exit命令，退出script，回到之前的终端。exit执行之前，包括exit命令，在history里都不会记录：</p>
<div class="highlight"><pre><span></span><code>$(OUT) history
......
  604  PS1=&#39;\$(OUT) &#39;
  605  script
  606  history
$(OUT)
</code></pre></div>

<p>另外，重复执行script会嵌套进入多层子进程中，不要转晕了：</p>
<div class="highlight"><pre><span></span><code>$ ps -ef | grep pts
steed       26    25  0 15:33 pts/0    00:00:00 bash -i
steed       33    26  0 15:33 pts/0    00:00:00 script
steed       34    33  0 15:33 pts/1    00:00:00 bash -i
steed       40    34  0 15:33 pts/1    00:00:00 script
steed       41    40  0 15:33 pts/2    00:00:00 bash -i
steed       48    41  0 15:34 pts/2    00:00:00 script
steed       49    48  0 15:34 pts/3    00:00:00 bash -i
steed       55    49  0 15:34 pts/3    00:00:00 script
steed       56    55  0 15:34 pts/4    00:00:00 bash -i
steed       93    56  0 15:36 pts/4    00:00:00 ps -ef
steed       94    56  0 15:36 pts/4    00:00:00 grep --color=auto pts
$ 
</code></pre></div>

<p>这里可以看出，script命令是先启动了一个bash。那么exit命令实际并不是退出script，而是退出bash，这个exit就是平时命令行中执行的exit。<br>
使用快捷键<code>Ctrl+d</code>的效果和exit一样。  </p>
<h5 id="ming-ling-yong-fa"><a class="toclink" href="#ming-ling-yong-fa">命令用法</a></h5>
<p>加上-h参数执行命令：</p>
<div class="highlight"><pre><span></span><code>$ script -h

用法：
 script <span class="o">[</span>选项<span class="o">]</span> <span class="o">[</span>文件<span class="o">]</span>

选项：
 -a, --append            追加输出
 -c, --command &lt;命令&gt;    运行命令而不是交互式 shell
 -e, --return            返回子进程的退出代码
 -f, --flush             每次 write<span class="o">(</span>写<span class="o">)</span> 后运行 flush<span class="o">(</span>冲刷<span class="o">)</span>
     --force             即使输出文件是链接也依然使用
 -q, --quiet             安静模式
 -t, --timing<span class="o">[=</span>&lt;文件&gt;<span class="o">]</span>   将时间数据输出到标准错误<span class="o">(</span>或文件<span class="o">)</span>
 -V, --version           输出版本信息并退出
 -h, --help              显示此帮助并退出

$ 
</code></pre></div>

<p>用法一目了然，还可以直接用-c参数来执行命令。  </p>
<h5 id="shi-yong-shi-li"><a class="toclink" href="#shi-yong-shi-li">使用示例</a></h5>
<p>下面是ansible命令使用的示例：</p>
<div class="highlight"><pre><span></span><code>$ script -c <span class="s1">&#39;ansible localhost -m debug&#39;</span> <span class="nb">test</span>
Script started, file is <span class="nb">test</span>
localhost <span class="p">|</span> <span class="nv">SUCCESS</span> <span class="o">=</span>&gt; <span class="o">{</span>
    <span class="s2">&quot;msg&quot;</span>: <span class="s2">&quot;Hello world!&quot;</span>
<span class="o">}</span>
Script <span class="k">done</span>, file is <span class="nb">test</span>
$ script -q -c <span class="s1">&#39;ansible localhost -m debug&#39;</span> <span class="nb">test</span>
localhost <span class="p">|</span> <span class="nv">SUCCESS</span> <span class="o">=</span>&gt; <span class="o">{</span>
    <span class="s2">&quot;msg&quot;</span>: <span class="s2">&quot;Hello world!&quot;</span>
<span class="o">}</span>
$ cat <span class="nb">test</span>
Script started on <span class="m">2020</span>-10-14 <span class="m">13</span>:45:03+08:00 <span class="o">[</span><span class="nv">TERM</span><span class="o">=</span><span class="s2">&quot;xterm-256color&quot;</span> <span class="nv">TTY</span><span class="o">=</span><span class="s2">&quot;/dev/tty1&quot;</span> <span class="nv">COLUMNS</span><span class="o">=</span><span class="s2">&quot;120&quot;</span> <span class="nv">LINES</span><span class="o">=</span><span class="s2">&quot;30&quot;</span><span class="o">]</span>
localhost <span class="p">|</span> <span class="nv">SUCCESS</span> <span class="o">=</span>&gt; <span class="o">{</span>
    <span class="s2">&quot;msg&quot;</span>: <span class="s2">&quot;Hello world!&quot;</span>
<span class="o">}</span>

Script <span class="k">done</span> on <span class="m">2020</span>-10-14 <span class="m">13</span>:45:04+08:00 <span class="o">[</span><span class="nv">COMMAND_EXIT_CODE</span><span class="o">=</span><span class="s2">&quot;0&quot;</span><span class="o">]</span>
$ 
</code></pre></div>

<p>第一次，在终端看到的输出，首行和尾行多了script命令的输出。<br>
第二次，加了-q参数，script命令就不会在终端输出了。<br>
最后，看一下文件中保存的内容，用cat打印的时候，是有颜色的。这里还有一个额外的好处，能看到开始和结束的时间。  </p>
<p>script本质上是一个录屏工具，额外存一份到文件中。所以终端的输出是没有任何变化的，这里会多出script命令本身的输出，可以用-q让script命令在终端上保持静默。<br>
另外存的一份文件，默认是typescript，也可以在最后加上路径和文件名指定保存的文件。  </p>
<h5 id="zai-crontab-zhong-wu-xiao"><a class="toclink" href="#zai-crontab-zhong-wu-xiao">在crontab中无效</a></h5>
<p>如果是要在计划任务中使用，由于终端是有输出的，所以需要做重定向：</p>
<div class="highlight"><pre><span></span><code>$ crontab -l
* * * * * script -q -c <span class="s1">&#39;/usr/local/bin/ansible localhost -m debug&#39;</span> -a /root/test-<span class="k">$(</span>date +<span class="se">\%</span>F<span class="k">)</span>.txt <span class="p">&amp;</span>&gt;/dev/null
$ 
</code></pre></div>

<p>想得很好，但是输出仍然没有颜色。script命令本质还是录屏。而程序是通过判断是否有终端，才选择是否要输出颜色。通过cron启动的任务是没有终端的，原本就不会有颜色，所以用script录下来的也是没有颜色的。  </p>
<h4 id="xiu-gai-pei-zhi-jie-jue"><a class="toclink" href="#xiu-gai-pei-zhi-jie-jue">修改配置解决</a></h4>
<p>其实ansible也是自带参数解决这个问题的。命令行参数不支持，但是有对应的配置项，可以修改配置文件或者ansible还支持读取环境变量。两种方式选择一种设置就好：</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span> <span class="s1">&#39;force_color = True&#39;</span> &gt;&gt; ansible.cfg
<span class="nb">export</span> <span class="nv">ANSIBLE_FORCE_COLOR</span><span class="o">=</span>True
</code></pre></div>

<p><em>早知有这个就不去试验script命令了。也没意识到去配置文件里找，而是先去试着在源码里搜了一下，然后才找到有对应的配置项。</em>  </p>
<h4 id="qu-chu-yan-se-ge-shi"><a class="toclink" href="#qu-chu-yan-se-ge-shi">去除颜色格式</a></h4>
<p>如果使用vi命令打开查看文件，是可以看到颜色的格式的，感觉文件变成了乱码，这里可以用sed命令来去除乱码。<br>
用下面的表达式来去除格式：</p>
<div class="highlight"><pre><span></span><code>sed <span class="s2">&quot;s|\x1B\[[0-9;]*[a-zA-Z]||g&quot;</span>
</code></pre></div>

<p>用重定向写入到新文件：</p>
<div class="highlight"><pre><span></span><code>sed <span class="s2">&quot;s|\x1B\[[0-9;]*[a-zA-Z]||g&quot;</span> test1 &gt; test2
</code></pre></div>

<p>直接修改源文件：</p>
<div class="highlight"><pre><span></span><code>sed -i <span class="s2">&quot;s|\x1B\[[0-9;]*[a-zA-Z]||g&quot;</span> test1
</code></pre></div>

<h3 id="ming-ling-xing-yin-cang-min-gan-xin-xi"><a class="toclink" href="#ming-ling-xing-yin-cang-min-gan-xin-xi">命令行隐藏敏感信息</a></h3>
<blockquote>
<p>在大多数的Linux/UNIX/OS X命令行上，每一个执行过的命令都会被存储在某种历史文件中（例如〜/.bash_history）。如果是以空格开头的命令，大多数命令行程序将跳过将该命令写入历史文件的操作。请注意，如果你的命令行默认情况下未启用此功能，可以将环境变量HISTCONTROL设置为ignoreboth来启用此功能。  </p>
</blockquote>
<p>有的系统用户环境默认开启，有的默认是不开启的。是通过环境变量控制的:</p>
<div class="highlight"><pre><span></span><code><span class="nb">export</span> <span class="nv">HISTCONTROL</span><span class="o">=</span>ignoreboth
</code></pre></div>

<p>第一次使用这个特性前先确认，最好再试一下。<br>
有必要的话，将这个环境变量的设置加到用户的<code>.bash_profile</code>文件里，仅针对登录的情况。  </p>
<p>以输入密码登录mysql为例子：</p>
<div class="highlight"><pre><span></span><code> mysql -uroot -pPASSWORD
</code></pre></div>

<p>只要在开头加一个空格，就可以避免暴露敏感信息。  </p>
<p>在执行复杂的命令时，不建议这么做。因为会隐藏掉整个命令的记录。这里需要保留命令的记录，但是隐藏掉敏感信息。<br>
应该先设置环境变量保存敏感信息，这条命令需要隐藏。然后再执行命令，引用环境变量：</p>
<div class="highlight"><pre><span></span><code> <span class="nb">export</span> <span class="nv">MYPASS</span><span class="o">=</span><span class="m">123456</span>
mysql -uroot -p<span class="nv">$MYPASS</span>
</code></pre></div>

<p>第一步，为敏感信息设置环境变量，隐藏这条命令。然后调用命令，使用环境变量来引用之前设置的敏感信息。  </p>
<p>一般来说，做到这个程度应该就可以了。  </p>
<h4 id="shi-yong-ming-ling-xing-you-hao-de-gong-ju"><a class="toclink" href="#shi-yong-ming-ling-xing-you-hao-de-gong-ju">使用命令行友好的工具</a></h4>
<p>还有一种更好的方法可以避免意外将机密信息以纯文本形式存储在磁盘上，例如pass(<a href="https://www.passwordstore.org">https://www.passwordstore.org</a>)。<br>
使用子进程安全地将机密信息从pass读取到环境变量中：</p>
<div class="highlight"><pre><span></span><code>mysql -uroot -p<span class="k">$(</span>pass database-password<span class="k">)</span>
</code></pre></div>

<p>这个pass命令需要从epel源安装。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>